/*
 *  
    Copyright (C) 2008  Nathaniel Waisbrot

    This program is free software: you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation, either version 3 of the License, or
    (at your option) any later version.

    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */
package termint.gui.graphics;

import org.eclipse.swt.SWT;
import org.eclipse.swt.graphics.Color;
import org.eclipse.swt.graphics.Font;
import org.eclipse.swt.graphics.FontMetrics;
import org.eclipse.swt.graphics.GC;
import org.eclipse.swt.graphics.Image;
import org.eclipse.swt.graphics.ImageData;
import org.eclipse.swt.widgets.Display;

import termint.gui.vt.VT100Color;
import termint.gui.vt.VTElement;
import termint.util.Pair;

public class TilesTextColor extends Tiles {	
	private static final String fontName = "Source Code Pro";
	private final int fontSize;
	protected final Color foreground;
	protected final Color nullColor;

	/**
	 * Create a new TilesTextColor, defaulting to a black background and a white foreground
	 * @param display
	 * @param fontSize
	 */
	public TilesTextColor(Display display, int fontSize) {
		this(display, 
				display.getSystemColor(SWT.COLOR_WHITE), 
				new Color(display, 0x20, 0x20, 0x20),
				display.getSystemColor(SWT.COLOR_BLACK), 
				fontSize, computeDimensions(display, fontSize));
	}
	
	/**
	 * Used by TilesImageBlock
	 */
	TilesTextColor(Display display, int fontSize, Pair<Integer,Integer> tileSize) {
		this(display, 
				display.getSystemColor(SWT.COLOR_WHITE), 
				new Color(display, 0x20, 0x20, 0x20),
				display.getSystemColor(SWT.COLOR_BLACK), 
				fontSize, tileSize);
	}
	
	private static Pair<Integer,Integer> computeDimensions(Display display, int fontSize) {
		GC gc = null;
		Image dummy = null;
		try {
			dummy = new Image(display, 1, 1);
			gc = new GC(dummy);
			gc.setFont(new Font(display, fontName, fontSize, SWT.NORMAL));
			FontMetrics metrics = gc.getFontMetrics();
			return new Pair<>(metrics.getAverageCharWidth(), metrics.getHeight());
		} finally {
			gc.dispose();
			dummy.dispose();
		}
	}
	
	/**
	 * Create a new TilesTextColor.
	 * @param display the display to draw on
	 * @param foreground default foreground color
	 * @param background default background color
	 * @param nullColor the color used for the character '\0'
	 * @param fontSize font size for drawing characters
	 */
	public TilesTextColor(Display display, Color foreground, Color background, Color nullColor, int fontSize, Pair<Integer,Integer> tileDims) {
		super(display, background);
		this.fontSize = fontSize;
		this.foreground = foreground;
		this.nullColor = nullColor;
		
		setTileSize(tileDims.a, tileDims.b);
				
		{	// set up a default tile for null chars
			nullImage = newImage();
			GC gc = new GC(nullImage);
			gc.setBackground(nullColor);
			gc.fillRectangle(nullImage.getBounds());
			gc.dispose();
		}
		
		{   // a little goofyness to make a transparent cursor
			Image cur = newImage();
			GC gc = new GC(cur);
			gc.setBackground(new Color(display, 0x60, 0x60, 0xFF));
			gc.fillRectangle(cur.getBounds());
			gc.dispose();
			ImageData d = cur.getImageData();
			d.alpha = 90;
			cur.dispose();
			cur = new Image(display, d);
			setCursor(cur);
		}
	}
	
	/**
	 * Maps VT100 color enums onto SWT color constants
	 * @param vtColor the VT100Color enum
	 * @return the SWT color constant
	 */
	private static int vt100ToSWTColor(VT100Color vtColor) {
		switch (vtColor) {
		case BLACK: return SWT.COLOR_BLACK;
		case WHITE: return SWT.COLOR_WHITE;
		case GREEN: return SWT.COLOR_GREEN;
		case BLUE: return SWT.COLOR_BLUE;
		case CYAN: return SWT.COLOR_CYAN;
		case MAGENTA: return SWT.COLOR_MAGENTA;
		case RED: return SWT.COLOR_RED;
		case YELLOW: return SWT.COLOR_YELLOW;
		default: return -1;
		}
	}
	
	@Override
	public Image getImage(VTElement key) {
		Image i = super.getImage(key);
		if (i == nullImage) {
			// no tile found for this.  Maybe create one?
			char c = key.getChar();
			if ((c >= 32) && (c < 128)) {
				// it's an ASCII char, so there *should* be a tile for it!
				int fontStyle = SWT.NORMAL;
				if (key.isBold())
					fontStyle |= SWT.BOLD;
				if (key.isUnderline())
					fontStyle |= SWT.UNDERLINE_SINGLE;
				Color bg = background;
				Color fg = foreground;
				if (key.getBg() != VT100Color.NONE)
					bg = display.getSystemColor(vt100ToSWTColor(key.getBg()));
				if (key.getFg() != VT100Color.NONE)
					fg = display.getSystemColor(vt100ToSWTColor(key.getFg()));
				if (key.isInvert()) {
					Color x = bg;
					bg = fg;
					fg = x;
				}
				i = makeChar(new Font(display, fontName, fontSize, fontStyle), c, bg, fg);
				this.setImage(key, i);
			}
		}
		return i;
	}

	protected Image makeChar(Font font, char c, Color bg, Color fg) {
		Image img = this.newImage();
		GC g = new GC(img);
		g.setBackground(bg);
		g.setForeground(fg);
		g.fillRectangle(img.getBounds());
		g.setFont(font);
		g.drawText(Character.toString(c), 0, 0, true);
		g.dispose();
		return img;
	}
	
	@Override
	protected void finalize() {
		super.finalize();
		background.dispose();
		foreground.dispose();
		nullColor.dispose();
	}
}
